package com.ucpaas.sms.service.smsAudit;

import com.alibaba.fastjson.JSON;
import com.hankcs.hanlp.HanLP;
import com.jsmsframework.audit.dto.JsmsAuditDTO;
import com.jsmsframework.audit.dto.JsmsAuditKeywordCategoryDTO;
import com.jsmsframework.audit.dto.JsmsAuditKeywordListAndCategoryDTO;
import com.jsmsframework.audit.entity.*;
import com.jsmsframework.audit.enums.AuditPage;
import com.jsmsframework.audit.enums.AuditType;
import com.jsmsframework.audit.exception.JsmsAuditException;
import com.jsmsframework.audit.service.*;
import com.jsmsframework.audit.util.DFAUtil4AuditUtil;
import com.jsmsframework.common.dto.JsmsPage;
import com.jsmsframework.common.dto.R;
import com.jsmsframework.common.dto.ResultVO;
import com.jsmsframework.common.enums.OperatorType;
import com.jsmsframework.common.enums.SmsTypeEnum;
import com.jsmsframework.common.enums.audit.AuditClientGroupIsDefault;
import com.jsmsframework.common.service.JsmsVtableService;
import com.jsmsframework.common.enums.audit.JsmsAuditStatus;
import com.jsmsframework.common.service.JsmsLogService;
import com.jsmsframework.common.util.BeanUtil;
import com.jsmsframework.common.util.DFAUtil;
import com.jsmsframework.common.util.DateUtil;
import com.jsmsframework.user.entity.JsmsAccount;
import com.jsmsframework.user.entity.JsmsClientInfoExt;
import com.jsmsframework.user.entity.JsmsUser;
import com.jsmsframework.user.service.JsmsAccountService;
import com.jsmsframework.user.service.JsmsClientInfoExtService;
import com.jsmsframework.user.service.JsmsUserService;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.ucpaas.sms.common.util.SpringContextUtils;
import com.ucpaas.sms.constant.LogConstant;
import com.ucpaas.sms.constant.DbConstant;
import com.ucpaas.sms.constant.LogConstant.LogType;
import com.ucpaas.sms.dao.MessageMasterDao;
import com.ucpaas.sms.entity.message.Channel;
import com.ucpaas.sms.entity.message.TestAccount;
import com.ucpaas.sms.enums.AuditPageName;
import com.ucpaas.sms.enums.AuditStatus;
import com.ucpaas.sms.enums.LogEnum;
import com.ucpaas.sms.enums.MobileOperatorEnum;
import com.ucpaas.sms.mapper.message.ChannelMapper;
import com.ucpaas.sms.mapper.message.TestAccountMapper;
import com.ucpaas.sms.model.*;
import com.ucpaas.sms.service.LogService;
import com.ucpaas.sms.util.*;
import com.ucpaas.sms.util.rest.utils.EncryptUtil;
import com.ucpaas.sms.util.rest.utils.JsonUtil;
import com.ucpaas.sms.util.web.AuthorityUtils;
import com.ucpaas.sms.util.web.StrutsUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.HtmlUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

import static com.jsmsframework.common.util.JsonUtil.toJson;

/**
 * 短信审核
 */
@SuppressWarnings("Duplicates")
@Service
public class SmsAuditServiceImpl implements SmsAuditService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SmsAuditServiceImpl.class);

    private ConcurrentMap<String, Object> concurrentMap = new ConcurrentHashMap<>();

    @Autowired
    private JsmsAuditKeywordListService jsmsAuditKeywordListService;
    @Autowired
    private JsmsLogService jsmsLogService;

    @Autowired
    private JsmsVtableService jsmsVtableService;
    @Autowired
    private  JsmsAuditkeywordRecord0Service jsmsAuditkeywordRecord0Service;

    /**
     * 重要客户
     */
    public final static String MAJOR_CLIENTS = "majorClients";

    /**
     * 待审核的验证码
     */
    public final static String YZM_NUM = "yzmNum";
    /**
     * 待发送的验证码
     */
    public final static String YZM_NUM_SENDING = "yzmNumSending";

    /**
     * 重要客户待审核的短信数量
     */
    public final static String MAJOR_NUM = "majorNum";
    /**
     * 重要客户待发送的短信数量
     */
    public final static String MAJOR_NUM_SENDING = "majorNumSending";
    /**
     * 普通待审核的短信数量(除了以上种类)
     */
    public final static String ORDINARY_NUM = "ordinaryNum";
    /**
     * 普通待发送的短信数量(除了以上种类)
     */
    public final static String ORDINARY_NUM_SENDING = "ordinaryNumSending";
    /**
     * 待审核总数量
     */
    public final static String AUDIT_NUM = "auditNum";
    /**
     * 待发送总数量
     */
    public final static String SEND_NUM = "sendNum";
    /**
     * 锁定数量
     */
    public final static String LOCK_NUM = "lockNum";
    public final static String MAJOR_LOCK_NUM = "majorLockNum";
    public final static String YZM_LOCK_NUM = "yzmLockNum";
    public final static String ORDINARY_LOCK_NUM = "ordinaryLockNum";
/*    Set<String> majorAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + MAJOR_NUM +":*");
    Set<String> yzmAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + YZM_NUM +":*");
    Set<String> ordinaryAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + AUDIT_NUM +":*");*/
    /**
     * 页面审核展示限制
     */
    public final static String SMS_AUDIT_LOCKED = "SMSAuditLocked:";
    /**
     * 页面审核展示限制
     */
    public final static String LIMIT = "limit";


    @Autowired
    private MessageMasterDao messageMasterDao;
    @Autowired
    private LogService logService;
    @Autowired
    private JsmsAuditService jsmsAuditService;
    @Autowired
    private JsmsAuditBakService jsmsAuditBakService;
    @Autowired
    private JsmsUserService jsmsUserService;
    @Autowired
    private JsmsAuditkeywordRecordService jsmsAuditkeywordRecordService;
    @Autowired
    private JsmsAuditKeywordCategoryService jsmsAuditKeywordCategoryService;

    @Autowired
    private JsmsClientInfoExtService jsmsClientInfoExtService;
    @Autowired
    private TestAccountMapper testAccountMapper;
    @Autowired
    private JsmsClientInfoExtService clientInfoExtService;
    @Autowired
    private JsmsAuditClientGroupService auditClientGroupService;
    @Autowired
    private ChannelMapper channelMapper;
    @Autowired
    private JsmsAccountService jsmsAccountService;



    private AudtiResultMQConfiguration audtiResultMQConfiguration;
    private ConnectionFactory factory;
    private Connection connection;
    private com.rabbitmq.client.Channel mqChannel;
    private Object rabbitMQInit = new Object();

    private static ConcurrentHashMap<String, TupleTwo<Map<String, Object>, DateTime>> clientAuditKeywordMap = new ConcurrentHashMap<>();

    /**
     * 缓存客户对应的关键字树，当修改关键字列表、类别、组别、用户配置时，需失效此缓存
     */
    private Map<String,DFAUtil4AuditUtil.DFANode4Audit<String>> dfaTreeCache = new ConcurrentHashMap<>();
    /**
     * 缓存短信审核的信息（审核过后需删除，或定时删除）
     */
    private Map<String,Map<String, Object>>  auditCache = new ConcurrentHashMap<>();

    @Override
    public void disableCache(final String clientId){
        ThreadPool.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                SmsAuditService smsAuditService = SpringContextUtils.getBean(SmsAuditService.class);
                smsAuditService.doDisable(clientId);
                smsAuditService.putClientAuditKeywordAndCategoryInCahche(clientId);
                return "完成缓存更新";
            }
        });
    }

    @Override
    public void disableCache(){
        dfaTreeCache = new ConcurrentHashMap<>();
        LOGGER.debug("失效所有的dfsTree");

    }

    @Override
    public List<String> doDisable(String clientId){
        List<String> clientIds = new ArrayList<>();
        if(clientId==null)
            return clientIds;

        LOGGER.debug("失效clientId={}的dfsTree",clientId);
        if(!"*".equals(clientId.trim())) {
            dfaTreeCache.remove(clientId);
            clientIds.add(clientId);
        }else { //失效默认用户组的关键字
            for (Map.Entry<String, DFAUtil4AuditUtil.DFANode4Audit<String>> entry : dfaTreeCache.entrySet()) {
                DFAUtil4AuditUtil.DFANode4Audit<String> root = entry.getValue();
                if(root==null||root.getDfaNodes()==null||root.getDfaNodes().isEmpty()){
                    clientIds.add(entry.getKey());
                }
                if(root.getAuditClientGroupIsDefault() !=null && AuditClientGroupIsDefault.默认组.equals(root.getAuditClientGroupIsDefault())){
                    clientIds.add(entry.getKey());
                }
            }
            LOGGER.debug("清除默认用户组的缓存, clientIds={}", com.jsmsframework.common.util.JsonUtil.toJson(clientIds));
            for(String c:clientIds){
                dfaTreeCache.remove(c);
            }
            LOGGER.debug("清除默认用户组的缓存, 完成");

        }

        List<String> auditIds = new ArrayList<>();
        for(String c:clientIds){

            for (Map.Entry<String,Map<String, Object>> entry :  auditCache.entrySet()) {
                Map<String,Object>  audit = entry.getValue();

                String auditClientId = (String) audit.get("clientid");
                if(auditClientId!=null){
                    if(auditClientId.equals(c)){
                        auditIds.add(entry.getKey());
                    }
                }

            }
        }
        LOGGER.debug("移除审核缓存,auditids={}", com.jsmsframework.common.util.JsonUtil.toJson(auditIds));
        for(String auditid:auditIds){
            auditCache.remove(auditid);
        }
        LOGGER.debug("移除审核缓存， 完成");

        return clientIds;
    }

    @Override
    public void disableCache(List<String> clientIds) {
        if(clientIds==null||clientIds.isEmpty())
            return;
//可能会有事务问题，所以取消了
//        for(final String clientId:clientIds){
//            ThreadPool.submit(new Callable<String>() {
//                @Override
//                public String call() throws Exception {
//                    SmsAuditService smsAuditService = SpringContextUtils.getBean(SmsAuditService.class);
//                    smsAuditService.doDisable(clientId);
//                    smsAuditService.putClientAuditKeywordAndCategoryInCahche(clientId);
//                    return "完成缓存更新";
//                }
//            });
//        }

        for(String clientId:clientIds){
            List<String> doneClientIds = this.doDisable(clientId);
            for(String c:doneClientIds) {
                this.putClientAuditKeywordAndCategoryInCahche(c);
            }
        }
    }

    @Override
    public void disableCacheNoRefresh(List<String> clientIds) {
        if(clientIds==null||clientIds.isEmpty())
            return;

        for(String clientId:clientIds){
            this.doDisable(clientId);
        }
    }

    @Override
    public PageContainer auditQueryPage(Map<String, String> params) {

        long start = System.currentTimeMillis();
        Map<String, Object> data = this.queryAuditRecord(AuditPageName.AUDIT_QUERY_PAGE, AuditPage.AUDIT_QUERY_PAGE, params);
        PageContainer pageDatas = (PageContainer) data.get("pageData");
        List<Map<String, Object>> pageData = pageDatas.getList();
        long end = System.currentTimeMillis();
        LOGGER.debug("【审核查询】查询审核记录耗时{}ms", end - start);

        // 将审核记录中的审核关键字标红
        long start2 = System.currentTimeMillis();
        pageData = this.markAuditKeywordByList(pageData);
        long end2 = System.currentTimeMillis();
        LOGGER.debug("【审核查询】加载关键字信息耗时{}ms", end2 - start2);

        pageDatas.setList(suppleClientInfo(pageData));
        return pageDatas;

    }

    /**
     * 补充客户标签信息
     *
     * @param page
     * @return
     */
    private List<Map<String, Object>> suppleClientInfo(List<Map<String, Object>> page) {
        Set clientIds = new TreeSet<>();
        for (Map<String, Object> map : page) {
            clientIds.add(map.get("clientid"));
        }
        if (!clientIds.isEmpty()) {
            List<JsmsClientInfoExt> clientInfoExts = clientInfoExtService.getByClientIds(clientIds);
            Map<String, String> clientLabelMap = new HashMap<>();
            for (JsmsClientInfoExt infoExt : clientInfoExts) {
                clientLabelMap.put(infoExt.getClientid(), infoExt.getClientLabel());
            }
            for (Map<String, Object> map : page) {
                String clientId = (String) map.get("clientid");
                if (StringUtils.isNotBlank(clientId)) {
                    map.put("clientLabel", clientLabelMap.get(clientId));
                }
            }
        }
        return page;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Map<String, Object>> auditPage(Map<String, String> params, AuditPageName kind, AuditPage auditPage) {

        /*Map<String, String> queryParams = new HashMap<>();
        queryParams.put("smsType", smsType);
        Map<String, Object> data = this.queryAuditRecord(kind, queryParams);*/
        long begin = System.currentTimeMillis();
        Map<String, Object> data = this.queryAuditRecord(kind, auditPage, params);
        List<Map<String, Object>> pageData = (List<Map<String, Object>>) data.get("pageData");
        LOGGER.debug("query audit list cost {}ms", System.currentTimeMillis()-begin);
        // 将审核记录中的审核关键字标红
        pageData = this.markAuditKeywordByList(pageData);
        return suppleClientInfo(pageData);

    }

    /**
     * 标红审核记录列表中的关键字
     *
     * @param page
     * @return
     */
    private List<Map<String, Object>> markAuditKeywordByList(List<Map<String, Object>> page)  {
        for (Map<String, Object> map : page) {
            long start2 = System.currentTimeMillis();
//            this.markAuditKeywordByMap(map);

            if(Objects.equals(map.get("status"), com.jsmsframework.common.enums.audit.AuditStatus.审核通过.getValue())|| Objects.equals(map.get("status"), com.jsmsframework.common.enums.audit.AuditStatus.审核不通过.getValue())){
                //从短信审核与关键字记录表匹配标记关键字
               try {
                   this.markAuditKeyWordByRecord(map);
               }catch (RuntimeException e){
                   LOGGER.error("【审核查询】历史标记一条审核记录的关键字失败",e);
                   throw new RuntimeException(e);

               }

                long end2 = System.currentTimeMillis();
                LOGGER.debug("【审核查询】历史标记一条审核记录的关键字耗时{}ms", end2 - start2);
            }else{
                //非审核通过及不通过的走实时匹配关键字
                //从短信审核与关键字记录表匹配标记关键字
                try {
                    this.markAuditKeywordByDFATree(map);
                }catch (RuntimeException e){
                    LOGGER.error("【审核查询】实时标记一条审核记录的关键字失败",e);
                    throw new RuntimeException(e);
                }
                long end2 = System.currentTimeMillis();
                LOGGER.debug("【审核查询】实时标记一条审核记录的关键字耗时{}ms", end2 - start2);
            }

        }
        return page;
    }


    /**
     * 标红单个审核记录中的关键字
     * t_sms_auditkeyword_record里记录的关键字标红
     * @param audit
     * @return
     */
    private List<String> markAuditKeyWordByRecord(Map<String,Object> audit){
        List<String> matchKeywordList = new ArrayList<>();
        Map<String,Object> params=new HashedMap();
        params.put("auditid",audit.get("auditid"));

        //查询记录表
        List<JsmsAuditkeywordRecord> records=jsmsAuditkeywordRecordService.queryAll(params);
        if(records!=null && !records.isEmpty()) {

            // 转移HTML防止注入，JSP页面输出是不能再用c:cout 因为下面需要显示标红的关键字
       //     String content = StringEscapeUtils.escapeHtml4(audit.get("content").toString());
            String content=UpaasHtmlUtils.Html2Text(audit.get("content").toString());
            // 将短信内容中的关键字用span标红
            String markContent=null;

            List<Integer> categoryIdList = new ArrayList<>();
            JsmsAuditKeywordCategoryDTO mostDangerousCategory = new JsmsAuditKeywordCategoryDTO();
            Integer categoryId = -1;
            Integer sort = -1;



            List<String> auditKeywordsList=new ArrayList<>();
            //关键字去重
            for (int i = 0; i < records.size()-1; i++) {
                for (int j = records.size()-1; j > i; j--) {
                    if (Objects.equals(records.get(j).getKeyword(), records.get(i).getKeyword())) {
                        records.remove(j);
                    }
                }
            }
            if(records.isEmpty()){
                auditKeywordsList=new ArrayList<>();
            }else {
                for (JsmsAuditkeywordRecord record : records) {
                    auditKeywordsList.add(record.getKeyword());
                    //查找列表最小的，危险程度最高的
                    matchKeywordList.add(record.getKeyword());
                    categoryIdList.add(record.getCategoryId());
                    if (record.getCategoryId() != null && record.getSort() != null) {
                        if (categoryId != -1 && sort != -1) {
                            if (record.getSort() < sort) {
                                categoryId = record.getCategoryId();
                                sort = record.getSort();
                            }
                        } else {
                            categoryId = record.getCategoryId();
                            sort = record.getSort();
                        }
                    }
                }
            }

            Map<String, Object> worldMap = KeyWrodSearchUtils.builWorldMap(auditKeywordsList);

            List<KeywordMatchTuple<String, Integer, Integer>> keywordMatchTuples = KeyWrodSearchUtils.searchKeywordPosByWorldMapSkipBlank(content, worldMap);

            // 将短信内容中的关键字用span标红
            int p1 = 0;
            int p2 = 0;
            List<String> htmlList = new ArrayList<>();

            for (KeywordMatchTuple<String, Integer, Integer> keywordMatchTuple : keywordMatchTuples) {
                matchKeywordList.add(keywordMatchTuple.keyword);
                int begin = keywordMatchTuple.start;
                int end = keywordMatchTuple.end;
                p2 = keywordMatchTuple.start;
                htmlList.add(content.substring(p1, p2));
                htmlList.add("<span style='color:red'>" + content.substring(begin, p1 = end) + "</span>");
            }
            htmlList.add(content.substring(p1));
            audit.put("contentWithmarked", StringUtils.join(htmlList, ""));



           /* for (JsmsAuditkeywordRecord record : records) {


                if(StringUtils.isBlank(markContent)){
                    markContent = content.replaceAll(record.getKeyword(), "<span style='color:red'>" + record.getKeyword() + "</span>");
                }else {
                    markContent = markContent.replaceAll(record.getKeyword(), "<span style='color:red'>" + record.getKeyword() + "</span>");
                }


                //繁体及大写无法匹配关键字，需要特殊处理

                    //强转繁体
                    String SimpleContent= HanLP.convertToSimplifiedChinese(content);
                    if(SimpleContent.indexOf(record.getKeyword())!=-1){
                        //匹配存在繁体，查出所在位置
                        List<Integer> indexs=new ArrayList<>();
                        int  start=SimpleContent.indexOf(record.getKeyword());

                        while (start !=-1){
                            indexs.add(start);
                            start=SimpleContent.indexOf(record.getKeyword(),start+1);
                           if(start!=-1){
                               indexs.add(start);
                           }
                        }
                        //对应标红转换过匹配位置
                        for (Integer index : indexs) {
                            String key=content.substring(index,index+record.getKeyword().length());
                            markContent = markContent.replaceAll(key, "<span style='color:red'>" + key+ "</span>");
                        }
                    }

                    //大小写
                    String lowerContent=content.toLowerCase();
                    if(lowerContent.indexOf(record.getKeyword())!=-1){
                        //匹配存在字母小写，查出所在位置
                        List<Integer> indexs=new ArrayList<>();
                        int  start=lowerContent.indexOf(record.getKeyword());

                        while (start !=-1){
                            indexs.add(start);
                            start=lowerContent.indexOf(record.getKeyword(),start+1);
                            if(start!=-1){
                                indexs.add(start);
                            }
                        }
                        //对应标红转换过匹配位置
                        for (Integer index : indexs) {
                            String key=content.substring(index,index+record.getKeyword().length());
                            markContent = markContent.replaceAll(key, "<span style='color:red'>" + key+ "</span>");
                        }
                    }




                //查找列表最小的，危险程度最高的
                matchKeywordList.add(record.getKeyword());
                categoryIdList.add(record.getCategoryId());
                if (record.getCategoryId() != null && record.getSort() != null) {
                    if (categoryId != -1 && sort != -1) {
                        if (record.getSort() < sort) {
                            categoryId = record.getCategoryId();
                            sort = record.getSort();
                        }
                    } else {
                        categoryId = record.getCategoryId();
                        sort = record.getSort();
                    }
                }


            }*/
           // audit.put("contentWithmarked", markContent);

            //找出危险最高的类别
            if (categoryId != -1 && sort != -1) {
                JsmsAuditKeywordCategory category = jsmsAuditKeywordCategoryService.getByCategoryId(categoryId);
               if(category!=null){
                   BeanUtil.copyProperties(category, mostDangerousCategory);
               }

            }

            if (mostDangerousCategory.getCategoryId() == null) {
                mostDangerousCategory = new JsmsAuditKeywordCategoryDTO();
                mostDangerousCategory.setCategoryColor("#f9f9f9");
                mostDangerousCategory.setCategoryName("");
            }
            audit.put("category", mostDangerousCategory);
            audit.put("categoryIdList", categoryIdList);

            audit.put("matchKeywordList", matchKeywordList);
            audit.put("cacheTime", new DateTime());

            // 结束短信内容标红，返回的是匹配到的关键字列表
            return matchKeywordList;
        }else {
            if(audit.get("audittime")!=null){
                //查询短信审核时间对应表
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date auditTime= null;
                try {
                    auditTime = sdf.parse(audit.get("audittime").toString());
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                Date monday=DateUtil.getThisWeekMonday(auditTime);

                SimpleDateFormat formatter=new SimpleDateFormat("yyyyMMdd");
                String mondayStr =formatter.format(monday);


                //查询前判断表是否存在
                String tableName= DbConstant.TablePrefix.t_sms_auditkeyword_record_+mondayStr;
                if(jsmsVtableService.getExistTable(tableName)){
                    params.put("tableDate",Long.valueOf(mondayStr));
                    //查询记录表
                    List<JsmsAuditkeywordRecord0> record0s=jsmsAuditkeywordRecord0Service.queryAll(params);
                    if(record0s!=null && !record0s.isEmpty()){

                        // 转移HTML防止注入，JSP页面输出是不能再用c:cout 因为下面需要显示标红的关键字
                     //   String content = StringEscapeUtils.escapeHtml4(audit.get("content").toString());
                        String content=UpaasHtmlUtils.Html2Text(audit.get("content").toString());
                        // 将短信内容中的关键字用span标红
                        String markContent=null;

                        List<Integer> categoryIdList = new ArrayList<>();
                        JsmsAuditKeywordCategoryDTO mostDangerousCategory = new JsmsAuditKeywordCategoryDTO();
                        Integer categoryId=-1;
                        Integer sort=-1;

                        List<String> auditKeywordsList=new ArrayList<>();
                        //关键字去重
                        for (int i = 0; i < record0s.size()-1; i++) {
                            for (int j = record0s.size()-1; j > i; j--) {
                                if (Objects.equals(record0s.get(j).getKeyword(), record0s.get(i).getKeyword())) {
                                    record0s.remove(j);
                                }
                            }
                        }
                        if(record0s.isEmpty()){
                            auditKeywordsList=new ArrayList<>();
                        }else {
                            for (JsmsAuditkeywordRecord0 record : record0s) {
                                auditKeywordsList.add(record.getKeyword());
                                //查找列表最小的，危险程度最高的
                                matchKeywordList.add(record.getKeyword());
                                categoryIdList.add(record.getCategoryId());
                                if (record.getCategoryId() != null && record.getSort() != null) {
                                    if (categoryId != -1 && sort != -1) {
                                        if (record.getSort() < sort) {
                                            categoryId = record.getCategoryId();
                                            sort = record.getSort();
                                        }
                                    } else {
                                        categoryId = record.getCategoryId();
                                        sort = record.getSort();
                                    }
                                }
                            }
                        }

                        Map<String, Object> worldMap = KeyWrodSearchUtils.builWorldMap(auditKeywordsList);

                        List<KeywordMatchTuple<String, Integer, Integer>> keywordMatchTuples = KeyWrodSearchUtils.searchKeywordPosByWorldMapSkipBlank(content, worldMap);

                        // 将短信内容中的关键字用span标红
                        int p1 = 0;
                        int p2 = 0;
                        List<String> htmlList = new ArrayList<>();

                        for (KeywordMatchTuple<String, Integer, Integer> keywordMatchTuple : keywordMatchTuples) {
                            matchKeywordList.add(keywordMatchTuple.keyword);
                            int begin = keywordMatchTuple.start;
                            int end = keywordMatchTuple.end;
                            p2 = keywordMatchTuple.start;
                            htmlList.add(content.substring(p1, p2));
                            htmlList.add("<span style='color:red'>" + content.substring(begin, p1 = end) + "</span>");
                        }
                        htmlList.add(content.substring(p1));
                        audit.put("contentWithmarked", StringUtils.join(htmlList, ""));



                        //去重
                        /*for (int i = 0; i < record0s.size()-1; i++) {
                            for (int j = record0s.size()-1; j > i; j--) {
                                if (Objects.equals(record0s.get(j).getKeyword(), record0s.get(i).getKeyword())) {
                                    record0s.remove(j);
                                }
                            }
                        }

                        for (JsmsAuditkeywordRecord0 record : record0s) {
                           // markContent=content.replaceAll(record.getKeyword(),"<span style='color:red'>" +record.getKeyword()+ "</span>");
                            if(StringUtils.isBlank(markContent)){
                                markContent = content.replaceAll(record.getKeyword(), "<span style='color:red'>" + record.getKeyword() + "</span>");
                            }else {
                                markContent = markContent.replaceAll(record.getKeyword(), "<span style='color:red'>" + record.getKeyword() + "</span>");
                            }
//繁体及大写无法匹配关键字，需要特殊处理

                            //强转繁体
                            String SimpleContent= HanLP.convertToSimplifiedChinese(content);
                            if(SimpleContent.indexOf(record.getKeyword())!=-1){
                                //匹配存在繁体，查出所在位置
                                List<Integer> indexs=new ArrayList<>();
                                int  start=SimpleContent.indexOf(record.getKeyword());

                                while (start !=-1){
                                    indexs.add(start);
                                    start=SimpleContent.indexOf(record.getKeyword(),start+1);
                                    if(start!=-1){
                                        indexs.add(start);
                                    }
                                }
                                //对应标红转换过匹配位置
                                for (Integer index : indexs) {
                                    String key=content.substring(index,index+record.getKeyword().length());
                                    markContent = markContent.replaceAll(key, "<span style='color:red'>" + key+ "</span>");
                                }
                            }

                            //大小写
                            String lowerContent=content.toLowerCase();
                            if(lowerContent.indexOf(record.getKeyword())!=-1){
                                //匹配存在字母小写，查出所在位置
                                List<Integer> indexs=new ArrayList<>();
                                int  start=lowerContent.indexOf(record.getKeyword());

                                while (start !=-1){
                                    indexs.add(start);
                                    start=lowerContent.indexOf(record.getKeyword(),start+1);
                                    if(start!=-1){
                                        indexs.add(start);
                                    }
                                }
                                //对应标红转换过匹配位置
                                for (Integer index : indexs) {
                                    String key=content.substring(index,index+record.getKeyword().length());
                                    markContent = markContent.replaceAll(key, "<span style='color:red'>" + key+ "</span>");
                                }
                            }




                            //查找列表最小的，危险程度最高的
                            matchKeywordList.add(record.getKeyword());
                            categoryIdList.add(record.getCategoryId());
                            if(record.getCategoryId()!=null && record.getSort()!=null){
                                if(categoryId!=-1 && sort !=-1){
                                    if(record.getSort()<sort){
                                        categoryId=record.getCategoryId();
                                        sort=record.getSort();
                                    }
                                }else {
                                    categoryId=record.getCategoryId();
                                    sort=record.getSort();
                                }
                            }


                        }
                        audit.put("contentWithmarked", markContent);*/

                        //找出危险最高的类别
                        if(categoryId!=-1 && sort !=-1){
                            JsmsAuditKeywordCategory category=jsmsAuditKeywordCategoryService.getByCategoryId(categoryId);
                            if(category!=null){
                                BeanUtil.copyProperties(category, mostDangerousCategory);
                            }
                        }

                        if (mostDangerousCategory.getCategoryId() == null) {
                            mostDangerousCategory = new JsmsAuditKeywordCategoryDTO();
                            mostDangerousCategory.setCategoryColor("#f9f9f9");
                            mostDangerousCategory.setCategoryName("");
                        }
                        audit.put("category",mostDangerousCategory);
                        audit.put("categoryIdList",categoryIdList);

                        audit.put("matchKeywordList",matchKeywordList);
                        audit.put("cacheTime",new DateTime());

                        // 结束短信内容标红，返回的是匹配到的关键字列表
                        return matchKeywordList;

                    }else {
                        LOGGER.debug("【审核查询】历史标记一条审核记录的关键字记录表无记录,走实时标记");
                        //空审核还是走实时匹配
                        this.markAuditKeywordByDFATree(audit);
                    }
                }else {
                    LOGGER.debug("【审核查询】历史标记一条审核记录的对应记录表不存在,走实时标记");
                    //空审核还是走实时匹配
                    this.markAuditKeywordByDFATree(audit);
                }

            }else {
                LOGGER.debug("【审核查询】历史标记一条审核记录的审核时间为空,走实时标记");
                //空审核还是走实时匹配
                this.markAuditKeywordByDFATree(audit);
            }
        }







        return matchKeywordList;
    }


    /**
     * 标红单个审核记录中的关键字
     * 使用markAuditKeywordByDFATree方法了
     * @param audit 审核记录
     * @return 返回的是匹配到的关键字
     */
    @Deprecated
    private List<String> markAuditKeywordByMap(Map<String, Object> audit) {
        // 查询该账号是否需要审核关键字   mark:这个检查感觉没什么必要
//        Integer needAuditKeywords = messageMasterDao.getOneInfo("smsAudit.getClientIdIsNeedAuditKeywords", clientid);

        String clientid = (String) audit.get("clientid");
        Map<String, Object> worldMap; // 这个map用来实现关键字标红查询
        if (clientAuditKeywordMap.containsKey(clientid)) {
            TupleTwo<Map<String, Object>, DateTime> tuple = (TupleTwo) clientAuditKeywordMap.get(clientid);
            DateTime now = new DateTime();
            DateTime expireTime = tuple.second.plusMinutes(ConfigUtils.audit_client_keyword_expire_time);

            // 判断关键字Map是否超时
            if (expireTime.isAfter(now)) {
                worldMap = tuple.first;
                LOGGER.debug("命中clientAuditKeywordMap");
            } else {
                // 关键字搜索Map不存在则调用下面方法构建并返回
                worldMap = this.putClientAuditKeywordInCahche(clientid);
            }

        } else {
            worldMap = this.putClientAuditKeywordInCahche(clientid);
        }

        // 转移HTML防止注入，JSP页面输出是不能再用c:cout 因为下面需要显示标红的关键字
     //   String content = StringEscapeUtils.escapeHtml4(audit.get("content").toString());
        String content=UpaasHtmlUtils.Html2Text(audit.get("content").toString());
        // 匹配当前内容中的关键字
        List<KeywordMatchTuple<String, Integer, Integer>> keywordMatchTuples = KeyWrodSearchUtils.searchKeywordPosByWorldMapSkipBlank(content, worldMap);

        // 将短信内容中的关键字用span标红
        int p1 = 0;
        int p2 = 0;
        List<String> htmlList = new ArrayList<>();
        List<String> matchKeywordList = new ArrayList<>();
        for (KeywordMatchTuple<String, Integer, Integer> keywordMatchTuple : keywordMatchTuples) {
            matchKeywordList.add(keywordMatchTuple.keyword);
            int begin = keywordMatchTuple.start;
            int end = keywordMatchTuple.end;
            p2 = keywordMatchTuple.start;
            htmlList.add(content.substring(p1, p2));
            htmlList.add("<span style='color:red'>" + content.substring(begin, p1 = end) + "</span>");
        }
        htmlList.add(content.substring(p1));
        audit.put("contentWithmarked", StringUtils.join(htmlList, ""));

        // 结束短信内容标红，返回的是匹配到的关键字列表
        return matchKeywordList;
    }


    /**
     * 标红单个审核记录中的关键字和添加类别信息
     *
     * @param audit 审核记录
     * @return 返回的是匹配到的关键字
     */
    @SuppressWarnings("Duplicates")
    private List<String> markAuditKeywordByDFATree(Map<String, Object> audit) {
        String auditid = audit.get("auditid").toString();

        Map<String,Object> cacheAudit = auditCache.get(auditid);
        if(cacheAudit!=null) {
            LOGGER.debug("找到audit缓存, 将原来audit={}", com.jsmsframework.common.util.JsonUtil.toJson(audit));
            audit.putAll(cacheAudit);
            LOGGER.debug("找到audit缓存, 更换为audit={}", com.jsmsframework.common.util.JsonUtil.toJson(audit));
            return (List<String>) audit.get("matchKeywordList");
        }


        // 转移HTML防止注入，JSP页面输出是不能再用c:cout 因为下面需要显示标红的关键字
      //  String content = StringEscapeUtils.escapeHtml4(audit.get("content").toString());
//        String content1 = StringEscapeUtils.escapeHtml4(audit.get("content").toString());
//        String content2 = StringEscapeUtils.escapeHtml3(audit.get("content").toString());
//        String content3=StringEscapeUtils.escapeEcmaScript(audit.get("content").toString());
    //    String content= HtmlUtils.htmlUnescape(audit.get("content").toString());

        String content=UpaasHtmlUtils.Html2Text(audit.get("content").toString());
  //      String content34 = audit.get("content").toString();
        String clientid = (String) audit.get("clientid");
        DFAUtil4AuditUtil.DFANode4Audit<String> dfaTree = this.putClientAuditKeywordAndCategoryInCahche(clientid);


        // 匹配当前内容中的关键字
        List<KeywordMatchTupleCategory<String, Integer, Integer,JsmsAuditKeywordCategory>> keywordMatchTuples = KeyWrodSearchUtils.searchKeywordPosByDFATreeSkipBlank(content, dfaTree);

        // 将短信内容中的关键字用span标红
        int p1 = 0;
        int p2 = 0;
        List<String> htmlList = new ArrayList<>();
        List<String> matchKeywordList = new ArrayList<>();
        List<Integer> categoryIdList = new ArrayList<>();
        List<JsmsAuditKeywordCategoryDTO> categoryList = new ArrayList<>();
        JsmsAuditKeywordCategoryDTO mostDangerousCategory = null;
        for (KeywordMatchTupleCategory<String, Integer, Integer,JsmsAuditKeywordCategory> keywordMatchTuple : keywordMatchTuples) {
            matchKeywordList.add(keywordMatchTuple.keyword);
            int begin = keywordMatchTuple.start;
            int end = keywordMatchTuple.end;
            p2 = keywordMatchTuple.start;
            htmlList.add(content.substring(p1, p2));
            LOGGER.debug("审核内容 ={}, 长度= {},开始位置={},结束位置={}",content,content.length(),begin,end);
            htmlList.add("<span style='color:red'>" + content.substring(begin, p1 = end) + "</span>");
            if(keywordMatchTuple.category!=null) {
                categoryIdList.add(keywordMatchTuple.category.getCategoryId());
                categoryList.add((JsmsAuditKeywordCategoryDTO) keywordMatchTuple.category);
                if (mostDangerousCategory == null) {
                    mostDangerousCategory = (JsmsAuditKeywordCategoryDTO) keywordMatchTuple.category;
                } else {
                    if (!mostDangerousCategory.equals(keywordMatchTuple.category)){
                        JsmsAuditKeywordCategoryDTO kCategory = (JsmsAuditKeywordCategoryDTO) keywordMatchTuple.category;
                        if(kCategory.getSort()<mostDangerousCategory.getSort()){
                            mostDangerousCategory = kCategory;
                        }
                    }
                }
            }
        }
        htmlList.add(content.substring(p1));
        audit.put("contentWithmarked", StringUtils.join(htmlList, ""));

        if (mostDangerousCategory == null) {
            mostDangerousCategory = new JsmsAuditKeywordCategoryDTO();
            mostDangerousCategory.setCategoryColor("#f9f9f9");
            mostDangerousCategory.setCategoryName("");
        }
        audit.put("category",mostDangerousCategory);
        audit.put("categoryIdList",categoryIdList);
        audit.put("categoryList",categoryList);

        audit.put("matchKeywordList",matchKeywordList);
        audit.put("cacheTime",new DateTime());
        auditCache.put(auditid,audit);

        // 结束短信内容标红，返回的是匹配到的关键字列表
        return matchKeywordList;
    }


    /**
     * 添加一个账号的审核关键字到本地内存
     *
     * @param clientid
     * @return
     */
    private Map<String, Object> putClientAuditKeywordInCahche(String clientid) {
        long start = System.currentTimeMillis();
        List<JsmsAuditClientGroup> clientGroups = auditClientGroupService.getKgroupIdsByClientId(clientid);
        List<Integer> keywordGroupIds = new ArrayList<>();
        for (JsmsAuditClientGroup clientGroup : clientGroups) {
            keywordGroupIds.add(clientGroup.getKgroupId());
        }
        List<String> auditKeywordsList;
        if (keywordGroupIds.isEmpty()) {
            auditKeywordsList = new ArrayList<>();
        } else {
            auditKeywordsList = messageMasterDao.selectList("smsAudit.getKeywordsByKGroupIds", keywordGroupIds);
        }

        Map<String, Object> worldMap = KeyWrodSearchUtils.builWorldMap(auditKeywordsList);
        TupleTwo<Map<String, Object>, DateTime> newKeyTuple = new TupleTwo(worldMap, new DateTime());
        clientAuditKeywordMap.put(clientid, newKeyTuple);
        LOGGER.debug("生成一个账号的关键字Map耗时{}ms", System.currentTimeMillis() - start);
        return worldMap;
    }


    /**
     * 添加一个账号的审核关键字和类别信息到本地内存
     *
     * @param clientid
     * @return
     */
    @Override
    public DFAUtil4AuditUtil.DFANode4Audit<String> putClientAuditKeywordAndCategoryInCahche(String clientid) {
        long start = System.currentTimeMillis();
        DFAUtil4AuditUtil.DFANode4Audit<String> keywordTree = dfaTreeCache.get(clientid);
        if(keywordTree==null) {
            List<JsmsAuditKeywordListAndCategoryDTO> jsmsAuditKeywordListAndCategoryDTOS = jsmsAuditKeywordListService.getListAndCategoryByClientId(clientid);

            keywordTree = DFAUtil4AuditUtil.buildHierarchicalDFATreeParent(jsmsAuditKeywordListAndCategoryDTOS, null);
            dfaTreeCache.put(clientid,keywordTree);
        }
        LOGGER.debug("生成账号{}的关键字DFA树(DFATree)耗时{}ms",clientid, System.currentTimeMillis() - start);
        return keywordTree;
    }


    /**
     * 更新短信审核状态
     */
    @Override
    public List<TestAccount> getTestClientid(Map params) {
        return testAccountMapper.queryParamsList(params);
    }

    /**
     * 更新短信审核状态
     */
    @Override
//    @Transactional
    public Map<String, Object> updateStatus(Map<String, String> params) throws Exception {
        String pageName = Objects.toString(params.get("pageName"), "");
        return updateStatus(params, AuditPageName.getInstance(pageName));
    }


    @Override
    @Transactional("message_new")
    public Map<String, Object> facadeUpdateStatus(Map<String, String> params, AuditPageName auditPageName){
        Map<String, Object> result = new HashMap<String, Object>();

        String auditIds = Objects.toString(params.get("auditIds"), "");
        String status = Objects.toString(params.get("status"), "0");
        String userId = Objects.toString(params.get("userId"), "");
        String transferToId = Objects.toString(params.get("transferToId"), "");
        String remark = Objects.toString(params.get("remark"), "");

        LOGGER.debug("userId={},auditPageName={}, params={}", auditPageName.getName(),toJson(params));
        List<String> auditIdList = new ArrayList<String>();

        if (StringUtils.isNotBlank(auditIds)) {
            auditIdList = Arrays.asList(auditIds.split(","));
        } else {
            result.put("result", "fail");
            result.put("msg", "审核ID不能为空");
            return result;
        }
        if (AuditStatus.WAIT_TO_AUDIT.getValue().equals(status)) { // 页面离开时释放待审核的记录

            // 删除Redis中保存的锁定记录
            LOGGER.debug("删除Redis中保存的锁定记录");
            this.delAuditIdInRedis(auditIdList, auditPageName);
            result.put("result", "success");

        } else {
            LOGGER.debug("更新短信审核状态为：{}，操作人={}，审核ID={}", JsmsAuditStatus.getDescByValue(Integer.valueOf(status)),
                    AuthorityUtils.getLoginRealName(), toJson(auditIdList));

            try {
                //0 校验参数
                JsmsAuditStatus updateStatus = null;
                if (JsmsAuditStatus.审核通过.getValue().toString().equals(status)) {
                    updateStatus = JsmsAuditStatus.审核通过;
                }else if (JsmsAuditStatus.审核不通过.getValue().toString().equals(status)) {
                    updateStatus = JsmsAuditStatus.审核不通过;

                }else if (JsmsAuditStatus.转审.getValue().toString().equals(status)) {
                    updateStatus = JsmsAuditStatus.转审;
                }else{
                    throw new JsmsAuditException("非法状态");
                }

                //1. 推送审核结果至MQ  //跟2017-12-26与廖家林确认, 重复放入同样的审核结果进MQ没问题, 他那么会处理
                boolean push = batchPublishAuditResultToMQ(auditIdList, status);

                // 2.删除Redis中保存的锁定记录
                this.delAuditIdInRedis(auditIdList, auditPageName);

                // 3. 更新订单状态
                List<Long> auditIdsLong = new ArrayList<>();
                for (String auditId : auditIdList) {
                    auditIdsLong.add(Long.valueOf(auditId));
                }
                int updateCount = 0;
                switch (updateStatus){
                    case 审核通过:
                        updateCount = jsmsAuditService.pass(auditIdsLong, userId, null);
                        break;
                    case 审核不通过:
                        updateCount = jsmsAuditService.nopass(auditIdsLong, userId, remark);
                        break;
                    case 转审:
                        updateCount = jsmsAuditService.transfer(auditIdsLong, userId, remark);
                        break;
                }
                result.put("result", "success");

                // 4.保存审核关键字
                if(updateCount>0){
                    insertKeyword(auditIdList, status);
                }else{
                    LOGGER.error("操作失败，记录已经被被审核或不存在");
                    result.put("result", "fail");
                    result.put("msg", "操作失败，记录已经被被审核或不存在");
                    LOGGER.debug("更新短信审核状态【失败】，操作人={}，操作信息={}", AuthorityUtils.getLoginRealName(), toJson(auditIdsLong));
                }


                // 5. 保存日志
                if (params.get("pageName") != null && params.get("pageName").equals("auditPage")) {
                    jsmsLogService.add(com.jsmsframework.common.enums.LogConstant.LogType.update, LogEnum.短信审核.getValue(),StrutsUtils.getRequestURI(), StrutsUtils.getClientIP(), AuthorityUtils.getLoginUserId().toString(), "短信审核 - 短信审核，修改审核记录状态：", params, result);
                } else {
                    jsmsLogService.add(com.jsmsframework.common.enums.LogConstant.LogType.update, LogEnum.短信审核.getValue(),StrutsUtils.getRequestURI(), StrutsUtils.getClientIP(), AuthorityUtils.getLoginUserId().toString(), "短信审核 - 短信审核查询，修改审核记录状态：", params, result);
                }

                // 6.完成业务后删除缓存
                if (updateCount > 0) {
                    LOGGER.debug("删除审核缓存");
                    for (String auditId : auditIdList) {
                        auditCache.remove(auditId);
                    }
                    LOGGER.debug("删除审核缓存, 完成");
                }
            }catch (IllegalArgumentException e){
                LOGGER.error("操作失败",e);
                result.put("result", "fail");
                result.put("msg",e.getMessage());
            }catch (JsmsAuditException je){
                LOGGER.error("操作失败",je);
                result.put("result", "fail");
                result.put("msg",je.getMessage());

            }catch (Exception ex){
                String s = "操作异常，请重新刷新页面后再尝试，或联系管理员";
                LOGGER.error(s,ex);
                result.put("result", "fail");
                result.put("msg",s);
            }
        }

        return result;

    }

    @Override
//    @Transactional
    @Deprecated
    public Map<String, Object> updateStatus(Map<String, String> params, AuditPageName auditPageName) throws Exception {
        Map<String, Object> result = new HashMap<String, Object>();

        String auditIds = Objects.toString(params.get("auditIds"), "");
        String status = Objects.toString(params.get("status"), "0");
        String userId = Objects.toString(params.get("userId"), "");
        String transferToId = Objects.toString(params.get("transferToId"), "");
        String remark = Objects.toString(params.get("remark"), "");

        LOGGER.debug("userId={},auditPageName={}, params={}", auditPageName.getName(), com.jsmsframework.common.util.JsonUtil.toJson(params));

        List<String> auditIdList = new ArrayList<String>();

        if (StringUtils.isNotBlank(auditIds)) {
            auditIdList = Arrays.asList(auditIds.split(","));
        } else {
            result.put("result", "fail");
            result.put("msg", "审核ID不能为空");
            return result;
        }


        try {
            if (AuditStatus.WAIT_TO_AUDIT.getValue().equals(status)) { // 页面离开时释放待审核的记录

                // 删除Redis中保存的锁定记录
                LOGGER.debug("删除Redis中保存的锁定记录");
                this.delAuditIdInRedis(auditIdList, auditPageName);
                result.put("result", "success");

            } else {

                boolean isRollback = false;
                Map<String, Object> sqlParams = new HashMap<String, Object>();
                sqlParams.put("releaseIdList", auditIdList);

                // todo

                /*if (!batchPublishAuditResultToMQ(auditIdList, status)) {
                    result.put("result", "fail");
                    result.put("msg", "操作失败，请稍后重试...");
                    return result;
                }*/

                sqlParams.put("status", status);

                // 转审时的信息
                if (AuditStatus.TRANSFER_AUDIT.getValue().equals(status)) {
                    sqlParams.put("transferperson", transferToId);

                } else {
                    sqlParams.put("auditperson", userId);

                }

                sqlParams.put("remark", remark);

                int i = messageMasterDao.update("smsAudit.updateStatus", sqlParams);
                if (i > 0) {

                    //插表记录关键字与审核关系
                    if (!AuditStatus.TRANSFER_AUDIT.getValue().equals(status)) {
                        /*for (String auditId : auditIdList) {
                            LOGGER.debug("记录关键字信息");
                            JsmsAudit audit = jsmsAuditService.getByAuditid(Long.valueOf(auditId));
                            audit.setStatus(Integer.valueOf(status));

                            LOGGER.debug("audit={}", com.jsmsframework.common.util.JsonUtil.toJson(audit));
                            Map<String, Object> auditMap = BeanUtil.beanToMap(audit, false);
                            List<String> keywordList = this.markAuditKeywordByMap(auditMap);
                            LOGGER.debug("keywords={}", com.jsmsframework.common.util.JsonUtil.toJson(keywordList));
                            List<JsmsAuditkeywordRecord> insertList = new ArrayList<>();
                            for (String kw : keywordList) {
                                JsmsAuditkeywordRecord record = new JsmsAuditkeywordRecord();
                                record.setAuditCreateTime(audit.getCreatetime());
                                record.setAuditStatus(Integer.valueOf(status));
                                record.setAuditid(audit.getAuditid());
                                record.setKeyword(kw);
                                insertList.add(record);
                            }

                            if (insertList.size() > 0) {
                                int insertNum = jsmsAuditkeywordRecordService.insertBatch(insertList);
                                if (insertNum <= 0) {
                                    result.put("result", "fail");
                                    result.put("msg", "操作失败，短信审核关键字记录表失败");
                                    LOGGER.debug("更新短信审核状态【失败】，操作人={}，，审核id为={},关键字为={}", AuthorityUtils.getLoginRealName(), audit.getAuditid(), JsonUtil.toJsonStr(keywordList));
                                }
                            }

                            publishAuditResultToMQ(audit);
                        }*/
                        boolean push = batchPublishAuditResultToMQ(auditIdList,status);
                        if(push){ // 推送成功
                            insertKeyword(auditIdList, status);
                        }else{ // 推送失败
                            LOGGER.debug("推送到MQ失败，准备手动回滚审核状态 ----------> start");
                            sqlParams.put("status", AuditStatus.WAIT_TO_AUDIT.getValue());
                            int revert = messageMasterDao.update("smsAudit.updateStatusRollback", sqlParams);
                            if(revert>0){
                                LOGGER.debug("更新数 = {}，回滚数 = {}，审核id ----------> {}",i,revert,JsonUtil.toJsonStr(auditIdList));
                                isRollback = true;
                            }
                            LOGGER.debug("推送到MQ失败，准备手动回滚审核状态 ----------> end");
                        }
                    }


                    // 删除Redis中保存的锁定记录
                    LOGGER.debug("删除Redis中保存的锁定记录");
                    this.delAuditIdInRedis(auditIdList, auditPageName);
                    result.put("result", "success");
                    LOGGER.debug("更新短信审核状态为：{}，操作人={}，审核ID={}", AuditStatus.getInstance(status).getName(),
                            AuthorityUtils.getLoginRealName(), JsonUtil.toJsonStr(auditIdList));
                    LOGGER.debug("删除审核缓存");
                    for (String auditId : auditIdList) {
                        auditCache.remove(auditId);
                    }
                    LOGGER.debug("删除审核缓存, 完成");
                } else {
                    LOGGER.error("操作失败，记录已经被被审核或不存在");
                    result.put("result", "fail");
                    result.put("msg", "操作失败，记录已经被被审核或不存在");
                    LOGGER.debug("更新短信审核状态【失败】，操作人={}，操作信息={}", AuthorityUtils.getLoginRealName(), JsonUtil.toJsonStr(sqlParams));
                }

                if (params.get("pageName") != null && params.get("pageName").equals("auditPage")) {
                    logService.add(LogType.update, LogEnum.短信审核.getValue(), "短信审核 - 短信审核，修改审核记录状态：", params, result);
                } else {
                    logService.add(LogType.update, LogEnum.短信审核.getValue(), "短信审核 - 短信审核查询，修改审核记录状态：", params, result);
                }

                if(isRollback){
                    String resultInvalidAuditId = null;
                    String invalidAuditId = null;
                    try {
                        for (String auditId : auditIdList) {
                            invalidAuditId = auditId;
                            JsmsAudit audit = jsmsAuditService.getByAuditid(Long.valueOf(auditId));
                        }
                    }catch (Exception e){
                        resultInvalidAuditId = invalidAuditId;
                        LOGGER.error("异常数据, invalidAuditId={}",resultInvalidAuditId,e);
                    }

                    String s = "操作失败，因为存在审核记录异常，审核已回滚，请重新审核，异常记录的审核ID="+invalidAuditId+"，请联系管理员处理或请跳过此审核记录，审核其他短信";
                    if(resultInvalidAuditId==null){
                        s = "操作失败，可能中间件出现异常，请联系管理员处理";
                    }
                    LOGGER.error(s);
                    result.put("result", "fail");
                    result.put("msg", s);
                }
            }
        } catch (Exception e) {
            throw e;
        }

        return result;
    }

    private void insertKeyword(List<String> auditIdList,String status){
        try {
            for (String auditId : auditIdList) {
                LOGGER.debug("记录关键字信息");
                JsmsAudit audit = jsmsAuditService.getByAuditid(Long.valueOf(auditId));
                audit.setStatus(Integer.valueOf(status));

                LOGGER.debug("audit={}", com.jsmsframework.common.util.JsonUtil.toJson(audit));
                Map<String, Object> auditMap = BeanUtil.beanToMap(audit, false);
                List<String> keywordList = this.markAuditKeywordByDFATree(auditMap);
                List<Integer> categoryIdList = (List<Integer>) auditMap.get("categoryIdList");
                List<JsmsAuditKeywordCategoryDTO> categoryList = (List<JsmsAuditKeywordCategoryDTO>) auditMap.get("categoryList");
                LOGGER.debug("keywords={}", com.jsmsframework.common.util.JsonUtil.toJson(keywordList));
                List<JsmsAuditkeywordRecord> insertList = new ArrayList<>();
                for(int i=0;i<keywordList.size();i++){
                    String kw = keywordList.get(i);
                    JsmsAuditkeywordRecord record = new JsmsAuditkeywordRecord();
                    record.setAuditCreateTime(audit.getCreatetime());
                    record.setAuditStatus(Integer.valueOf(status));
                    record.setAuditid(audit.getAuditid());
                    JsmsAuditKeywordCategoryDTO category = null;
                    try{
                        category = categoryList.get(i);
                        if(category!=null){
                            record.setCategoryId(category.getCategoryId());
                            record.setSort(category.getSort());
                        }
                    }catch (Exception e){
                        LOGGER.error("获取categoryId异常, i={}, categoryIdList={}",i, com.jsmsframework.common.util.JsonUtil.toJson(categoryIdList),e);
                    }
                    record.setKeyword(kw);
                    insertList.add(record);
                }

                if (insertList.size() > 0) {
                    int insertNum = jsmsAuditkeywordRecordService.insertBatch(insertList);
                    if (insertNum <= 0) {
                        /*result.put("result", "fail");
                        result.put("msg", "操作失败，短信审核关键字记录表失败");*/
                        LOGGER.debug("更新短信审核状态【失败】，操作人={}，，审核id为={},关键字为={}", AuthorityUtils.getLoginRealName(), audit.getAuditid(), JsonUtil.toJsonStr(keywordList));
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("短信审核关键字记录表失败 ---> ",e);
        }
    }


    /**
     * todo
     * @param
     * @return
     */
    private boolean batchPublishAuditResultToMQ(List<String> auditIdList, String auditStatus) {
        boolean flag = true;
        LOGGER.debug("将审核结果放入MQ -------------------> start, auditStatus={}",auditStatus);
        try {
            if (!AuditStatus.TRANSFER_AUDIT.getValue().equals(auditStatus)) {
                for (String auditId : auditIdList) {
                    LOGGER.debug("推送审核结果到MQ auditId-->{}",auditId);
                    JsmsAudit audit = jsmsAuditService.getByAuditid(Long.valueOf(auditId));
                    LOGGER.debug("将单条审核结果放入MQ -------------------> start, 推送审核结果到MQ -->, audit={}", JSON.toJSONString(audit));
                    audit.setStatus(Integer.valueOf(auditStatus));

                    publishAuditResultToMQ(audit);
                    LOGGER.debug("将单条审核结果放入MQ -------------------> end");
                }
            }
        } catch (Exception e) {
            LOGGER.error("推送审核结果到MQ auditIdList --> {}", auditIdList);
            LOGGER.error("推送审核结果到MQ 失败 --> ", e);
            flag = false;
        }
        LOGGER.debug("将审核结果放入MQ -------------------> end");
        return flag;
    }


    private void publishAuditResultToMQ(JsmsAudit audit) throws Exception {
        StringBuffer message = new StringBuffer();
        message.append("auditcontent=" + audit.getMd5());
        message.append("&auditid=" + audit.getAuditid());
        message.append("&status=" + audit.getStatus());
        LOGGER.debug("推送消息message={},使用mq信息为: {}", message.toString(), audtiResultMQConfiguration.toString());
        if (mqChannel == null || !mqChannel.isOpen()) {
            LOGGER.debug("channel已断开");
            try {
                mqChannel = connection.createChannel();
            } catch (Exception e) {
                LOGGER.error("创建mqchannel失败", e);
                LOGGER.debug("重新连接Rabbitmq");
                this.connection = factory.newConnection();
                LOGGER.debug("连接Rabbitmq成功");
                mqChannel = connection.createChannel();
            }
            this.mqChannel.exchangeDeclare(audtiResultMQConfiguration.getMqExchange(), "direct", true);
            this.mqChannel.queueBind(audtiResultMQConfiguration.getQueueName(), audtiResultMQConfiguration.getMqExchange(), audtiResultMQConfiguration.getMqRoutingkey());
            LOGGER.debug("创建mqchannel成功");
        }
        mqChannel.basicPublish(audtiResultMQConfiguration.getMqExchange(), audtiResultMQConfiguration.getMqRoutingkey(), null, message.toString().getBytes());
//        this.mqChannel.close();
        LOGGER.debug("推送消息完成");
    }

    @Override
    public AudtiResultMQConfiguration getAudtiResultMQConfiguration() {
        return audtiResultMQConfiguration;
    }


    public void setAudtiResultMQConfiguration(AudtiResultMQConfiguration audtiResultMQConfiguration) throws IOException, TimeoutException {
        synchronized (rabbitMQInit) {
            if (this.audtiResultMQConfiguration != null && this.audtiResultMQConfiguration.equals(audtiResultMQConfiguration)) { //配置未修改
                return;
            } else { //配置已修改
                this.audtiResultMQConfiguration = audtiResultMQConfiguration;
                try {
                    if (mqChannel != null)
                        mqChannel.close();
                    if (connection != null)
                        connection.close();
                } catch (Exception e) {
                    LOGGER.error("", e);
                } finally {
                    mqChannel = null;
                    connection = null;
                    factory = null;
                }
            }
            if (this.factory == null) {
                LOGGER.debug("初始化存放审核结果的MQ");
                LOGGER.debug("audtiResultMQConfiguration={}", com.jsmsframework.common.util.JsonUtil.toJson(audtiResultMQConfiguration));

                this.factory = new ConnectionFactory();
                this.factory.setHost(audtiResultMQConfiguration.getIp());
                this.factory.setPort(audtiResultMQConfiguration.getPort());
                this.factory.setVirtualHost(audtiResultMQConfiguration.getVirtualHost());
                this.factory.setUsername(audtiResultMQConfiguration.getUsername());
                this.factory.setPassword(audtiResultMQConfiguration.getPassword());
                this.factory.setConnectionTimeout(3000);

                try {
                    this.connection = factory.newConnection();
                    LOGGER.debug("连接Rabbitmq成功");
                } catch (Exception e) {
                    LOGGER.error("【RabbitMq】：创建connection失败 " + e);
                    throw e;
                }

                try {
                    this.mqChannel = this.connection.createChannel();
                    LOGGER.debug("创建channel成功");
                    this.mqChannel.exchangeDeclare(audtiResultMQConfiguration.getMqExchange(), "direct", true);
                    this.mqChannel.queueBind(audtiResultMQConfiguration.getQueueName(), audtiResultMQConfiguration.getMqExchange(), audtiResultMQConfiguration.getMqRoutingkey());
                } catch (Exception e) {
                    LOGGER.error("【RabbitMq】：创建channel失败 " + e);
                    throw e;
                }
                LOGGER.debug("初始化存放审核结果的MQ成功");
            }
        }

    }

    /**
     * 更新短信审核状态
     */
    @Override
    public ResultVO testSendAction(Map<String, String> params) {

        final TestSendRequest testSend = new TestSendRequest();
        testSend.setClientid(params.get("clientid"));
        testSend.setMobile(params.get("mobile"));
        testSend.setSmstype(params.get("smstype"));
        testSend.setContent(params.get("content"));
        testSend.setExtend(params.get("extend"));
        testSend.setChannelid(params.get("channelid"));

        if (!RegexUtils.isClientId(testSend.getClientid()))
            return ResultVO.failure("用户账号不能为空或者格式不对");

        if (StringUtils.isBlank(testSend.getMobile()))
            return ResultVO.failure("手机号不能为空");

        if (StringUtils.isBlank(testSend.getSmstype()))
            return ResultVO.failure("请选择短信类型");

        if (StringUtils.isNotBlank(testSend.getExtend()) && !testSend.getExtend().matches("^\\d{0,12}$"))
            return ResultVO.failure("扩展位数只能是12位以内数字组合");

        if (StringUtils.isBlank(testSend.getContent()))
            return ResultVO.failure("请输入测试短信内容");

        if (testSend.getContent().length() > 500)
            return ResultVO.failure("短信内容不能超过500");

        if (!testSend.getContent().matches("^(【[^\\n]{2,12}】[^【】]{1,496})|([^【】]{1,496}【[^\\n]{2,12}】)$"))
            return ResultVO.failure("请输入正确格式的短信");

        String[] mobileArr = testSend.getMobile().split(",");
        for (String mobile : mobileArr) {
            if (!RegexUtils.isMobile(mobile))
                return ResultVO.failure("号码格式不正确");
        }

        ResultVO resultVO = null;
        if (StringUtils.isNotBlank(testSend.getChannelid()))
            resultVO = checkOperatorstype(Integer.parseInt(testSend.getChannelid()), testSend.getMobile());

        if (resultVO != null && resultVO.isFail())
            return resultVO;

        JsmsAccount jsmsAccount = jsmsAccountService.getByClientId(testSend.getClientid());
        if (jsmsAccount == null)
            return ResultVO.failure("客户账号不存在");

//        testSend.setClientid("a00025");// todo --> 注释掉
        try {
            String md5Digest = EncryptUtil.md5Digest(jsmsAccount.getPassword());
//            String md5Digest = EncryptUtil.md5Digest("yzxwarn1");// todo --> 注释掉
            testSend.setPassword(md5Digest.toLowerCase());
        } catch (Exception e) {
            e.printStackTrace();
        }

        String configUrl = ConfigUtils.sms_test_send_url;
//        String configUrl = "https://api.ucpaas.com/sms-partner/access/{clientid}/sendsms";// todo --> 注释掉
        final String testSendUrl = ConfigUtils.sms_test_send_url.replaceFirst("\\{[^\\}]*\\}", testSend.getClientid());
//        final String testSendUrl = configUrl.replaceFirst("\\{[^\\}]*\\}", testSend.getClientid());// todo --> 注释掉
        LOGGER.debug("请求的地址 -----------------------------> {}", testSendUrl);
        ExecutorService exec = Executors.newFixedThreadPool(1);
        FutureTask futureTask = new FutureTask(new Callable() {
            @Override
            public String call() throws Exception {
                LOGGER.debug("测试短信发送的线程 ----------> start");
                String resp = null;
                // 线上https
                LOGGER.debug("测试短信发送参数 ----------> {}", JsonUtils.toJson(testSend));

                if (testSendUrl.startsWith("https")) {
                    resp = HttpUtils.httpPost(testSendUrl, JsonUtils.toJson(testSend), true);
                    LOGGER.debug("测试短信发送的的响应内容 ----------> {}", resp);
                } else {
                    resp = HttpUtils.httpPost(testSendUrl, JsonUtils.toJson(testSend), false);
                    LOGGER.debug("测试短信发送的的响应内容 ----------> {}", resp);
                }
                LOGGER.debug("测试短信发送的线程 ----------> start");
                return resp;
            }
        });
        exec.submit(futureTask);
        String resp = null;
        try {
            resp = (String) futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


        LOGGER.debug("短信审核 - 短信发送测试：{}", resp);
        logService.add(LogType.update, LogEnum.短信审核.getValue(), "短信审核 - 短信发送测试", JsonUtils.toJson(testSend), resp);
        exec.shutdown();
        return ResultVO.successDefault(resp);
    }

    /**
     * 检查通道号和手机号运营商类型是否匹配
     */
    private ResultVO checkOperatorstype(Integer channelId, String mobiles) {
        String[] mobileArr = mobiles.split(",");
        if (mobileArr.length > 100)
            return ResultVO.failure("号码不能超过100个");

        Channel channel = channelMapper.getByCid(channelId);

        if (OperatorType.全网.getValue().equals(channel.getOperatorstype()))
            return ResultVO.successDefault();

        for (String mobile : mobileArr) {

            String mobileOperator = RegexUtils.getMobileOperator(mobile);
            if (!channel.getOperatorstype().toString().equals(mobileOperator))
                return ResultVO.failure("通道所属运营商类型：" + OperatorType.getDescByValue(channel.getOperatorstype())
                        + "<br/>号码：" + mobile + "为" + MobileOperatorEnum.getDescByValue(mobileOperator));

        }
        return ResultVO.successDefault();
    }

    /**
     * 查询短信审核记录<br>
     * 该方法使用同步防止不同用户同一时间进入页面时锁定相同的记录<br>
     *
     * @param auditKind       页面枚举
     * @param queryConditions 页面的查询条件
     * @return
     */
    private Map<String, Object> queryAuditRecord(AuditPageName auditKind, AuditPage auditPage, Map<String, String> queryConditions) {
        Map<String, Object> result = new HashMap<String, Object>();

        LOGGER.debug("进入{},审核人={}", auditKind.getName(), AuthorityUtils.getLoginRealName());

        String loginUserId = String.valueOf(AuthorityUtils.getLoginUserId());
        String loginUserName = AuthorityUtils.getLoginRealName();
        List<String> waitLockedList = new ArrayList<>(); // 当前查询需要被锁定的记录
        if (AuditPageName.AUDIT_QUERY_PAGE.equals(auditKind)) {// 审核查询页面
            PageContainer pageContainer = new PageContainer();
            pageContainer.setPageRowCount(100);// 默认每页100条数据
            pageContainer.setPageRowArray(new Integer[]{10, 30, 50, 100, 200, 500});
            pageContainer = messageMasterDao.getSearchPage("smsAudit.query", "smsAudit.queryCount", queryConditions, pageContainer);
            Set<String> keySet = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + "*");
            // 查询已经被锁定的审核记录
            TreeSet<Long> lockedAuditids = new TreeSet<>();
            Map<String, String> auditIdLockedMap = new HashMap<>(); // 已经被锁定的记录
            if (keySet != null && !keySet.isEmpty()) {
                for (String key : keySet) {
                    String[] array = key.split(":");
                    String auditid = array[array.length - 1];
                    lockedAuditids.add(Long.parseLong(auditid));
                    auditIdLockedMap.put(auditid, key);
                }
            }

            LOGGER.debug("当前已经锁定的审核记录共={}条，详细信息={}", auditIdLockedMap.size(), auditIdLockedMap);
            if (!auditIdLockedMap.isEmpty()) {
                for (Map<String, Object> map : pageContainer.getList()) {
                    String auditid = String.valueOf(map.get("auditid"));

                    // 获得锁定人的信息
                    if (auditIdLockedMap.get(auditid) != null) {
                        // 如果Redis中存在说明已经被锁定，获取其中的信息
                        Map<String, String> lockInfo = RedisUtils.hgetallSpecificDb(6, auditIdLockedMap.get(auditid));
                        map.put("lockByUserId", lockInfo.get("userid"));
                        map.put("lockByUserName", lockInfo.get("username"));
                    } else {
                        // 当前用户只能锁定status = 0 或者(status = 3 && transferperson 等于自己) 的记录
                        map.put("lockByUserId", "");
                        map.put("lockByUserName", "");
                    }

                }
            }

            result.put("pageData", pageContainer);

        } else {
            synchronized (SmsAuditServiceImpl.class) {


                Set<String> keySet = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + auditKind.getValue() + ":*");
                // 查询已经被锁定的审核记录
                TreeSet<Long> lockedAuditids = new TreeSet<>();
                List<String> auditIdLockedList = new ArrayList<>(); // 已经被锁定的记录
                if (keySet != null && !keySet.isEmpty()) {
                    for (String key : keySet) {
                        String[] array = key.split(":");
                        String auditid = array[array.length - 1];
                        lockedAuditids.add(Long.parseLong(auditid));
                        auditIdLockedList.add(auditid);
                    }
                }

                LOGGER.debug("当前已经锁定的审核记录共={}条，详细信息={}", auditIdLockedList.size(), auditIdLockedList);

//			 	if(AuditPageName.AUDIT_PAGE.equals(auditPageName)){// 审核页面
                Date startCreateTime = null;
                Date endCreateTime = null;
                try {
                    if (StringUtils.isNoneBlank(queryConditions.get(""))) {
                        startCreateTime = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").parse(queryConditions.get("start_time"));
                    }
                    if (StringUtils.isNoneBlank(queryConditions.get(""))) {
                        endCreateTime = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").parse(queryConditions.get("end_time"));
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                /* todo
                List<JsmsAudit> jsmsAuditList = jsmsAuditService.queryAuditRecord(queryConditions.get("clientid"), AuthorityUtils.getLoginUserId(), (TreeSet) concurrentMap.get(MAJOR_CLIENTS),
                        lockedAuditids, queryConditions.get("content"), startCreateTime, endCreateTime, queryConditions.get("sign"),
                        Integer.parseInt(queryConditions.get("smsType")), Integer.parseInt(queryConditions.get("lessSendnum")),
                        Integer.parseInt(queryConditions.get("greaterSendnum")), Long.parseLong(queryConditions.get("auditid")), auditPage, Integer.parseInt(queryConditions.get("limit")));
                */
                Map<String, Object> sqlParams = new HashMap<String, Object>();
                sqlParams.put("sms_audit_lock", auditIdLockedList);
                sqlParams.put("transferperson", loginUserId);
                sqlParams.putAll(queryConditions); // 审核页面审核的短信类型
                List<Map<String, Object>> auditPageList = new ArrayList<>();
                long auditPageListBegin = System.currentTimeMillis();
                if (AuditPageName.ORDINARY_NUM.equals(auditKind)) {// 普通审核页面
                    sqlParams.put("clientIds", concurrentMap.get(MAJOR_CLIENTS));
                    auditPageList = messageMasterDao.getSearchList("smsAudit." + ORDINARY_NUM, sqlParams);
                } else if (AuditPageName.YZM_AUDIT_PAGE.equals(auditKind)) {
                    auditPageList = messageMasterDao.getSearchList("smsAudit." + YZM_NUM, sqlParams);
                } else if (AuditPageName.MAJOR_AUDIT_PAGE.equals(auditKind)) {
                    Set<String> clientIds = (Set<String>) concurrentMap.get(MAJOR_CLIENTS);
                    if (clientIds != null && !clientIds.isEmpty()) {
                        sqlParams.put("clientIds", concurrentMap.get(MAJOR_CLIENTS));
                        auditPageList = messageMasterDao.getSearchList("smsAudit." + MAJOR_NUM, sqlParams);
                    }
                }
                LOGGER.debug("query auditPageList cost {}ms",System.currentTimeMillis()-auditPageListBegin);

                for (Map<String, Object> map : auditPageList) {
                    waitLockedList.add(String.valueOf(map.get("auditid")));
                }
                result.put("pageData", auditPageList);

//				}else if(){}
                LOGGER.debug("当前查询后需要新增的锁定的记录有{}条，详细信息={}", waitLockedList.size(), waitLockedList);
                this.hmsetAuditIdInRedis(waitLockedList, auditKind);
            }


            // 将需要锁定的审核记录保存到Redis中
        }

        return result;
    }

    /**
     * 将锁定的审核记录保存到Redis中
     *
     * @return
     */
    private void hmsetAuditIdInRedis(List<String> auditIdList, AuditPageName auditKind) {
        // 获得所有锁定的key
        Map<String, String> hash = new HashMap<>();
        hash.put("auditid", "");
        hash.put("userid", String.valueOf(AuthorityUtils.getLoginUserId()));
        hash.put("username", AuthorityUtils.getLoginRealName());
        hash.put("createtime", DateTime.now().toString("yyyyMMddHHmmss"));

        int auditExpireTime = (int) this.getAuditExpireTime().get("auditExpireTime");
        // Redis中的审核锁定记录比页面审核超时时间长30秒
        int redisExpireTime = auditExpireTime * 60 + 30;
        List<String> tempList = new ArrayList<>();
        if (auditIdList != null && !auditIdList.isEmpty()) {
            Jedis jedis = null;
            try {
                jedis = RedisUtils.getJedis();
                Pipeline pipeline = jedis.pipelined();
                pipeline.select(6);
                for (String auditId : auditIdList) {
                    String key = SMS_AUDIT_LOCKED + auditKind.getValue() + ":" + auditId;
                    key = key.toLowerCase();
                    hash.put("auditid", auditId);
                    tempList.add(key);
                    pipeline.hmset(key, hash);
                    pipeline.expire(key, redisExpireTime);
                }
                pipeline.sync();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
        }
        LOGGER.debug("保存审核锁定记录到Redis中，锁定人={}，锁定记录={}", AuthorityUtils.getLoginRealName(), tempList);

    }

    /**
     * 删除Redis中的锁定审核记录
     *
     * @param auditIdList
     */
    private void delAuditIdInRedis(List<String> auditIdList, AuditPageName pageKind) {

        LOGGER.debug("删除Redis中保存的锁定记录");
        /*Jedis jedis = null;
        try {
            jedis = RedisUtils.getJedis();
            Pipeline pipeline = jedis.pipelined();
            pipeline.select(6);
            for (String auditId : auditIdList) {
                String key = SMS_AUDIT_LOCKED + pageKind.getValue() + ":" + auditId;
                hash.put("auditid", auditId);
                tempList.add(key);
                pipeline.hmset(key, hash);
                pipeline.expire(key, redisExpireTime);
            }
            pipeline.sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }*/

        // redis中锁定的审核记录 key = SMS_AUDIT_KEY_PREFIX + auditId

        // 获得所有锁定的key
        List<String> tempList = new ArrayList<>();
        if (auditIdList != null && !auditIdList.isEmpty()) {
            for (String auditId : auditIdList) {
                tempList.add(SMS_AUDIT_LOCKED + pageKind.getValue() + ":" + auditId); // todo  + audit
            }
        }
        String[] keys = tempList.toArray(new String[tempList.size()]);

        // 审核锁定记录保存在db 6
        int index = 6;

        // 删除db 6中的审核记录
        RedisUtils.delKeySpecifiedDb(index, keys);

        LOGGER.debug("删除Redis中锁定记录，被删除的锁定记录={}", tempList);
    }

    @Override
    public Map getKindsAuditNum() {
        checkLockNum(concurrentMap);
        return concurrentMap;
    }

    @Override
    public Map<String, Object> getKindsAuditNum(String recordCount, String auditPageName) {
        checkLockNum(concurrentMap);
        Map<String, Object> result = new HashMap(concurrentMap);
        if(StringUtils.isNotBlank(recordCount)&&StringUtils.isNotBlank(auditPageName)) {
            long rc = Long.valueOf(recordCount);
            long auditNum = 0;                                                          //待审核短信数量(总的)
//            long auditNumSending = 0;                                                   //审核待发送数(总的)
            long yzmNum = 0;                                                            //待审核短信数量(验证码短信审核)
//            long yzmNumSending = 0;                                                     //审核待发送数(验证码短信审核)
            long majorNum = 0;                                                          //待审核短信数量(重点客户短信审核)
//            long majorNumSending = 0;                                                   //审核待发送数(重点客户短信审核)
            long ordinaryNum = 0;                                                       //待审核短信数量(普通短信)
//            long ordinaryNumSending = 0;                                                //审核待发送数(普通短信)

//            auditNum = concurrentMap.get(AUDIT_NUM) == null ? 0 : Long.valueOf(concurrentMap.get(AUDIT_NUM).toString());
//            auditNumSending = concurrentMap.get(SEND_NUM) == null ? 0 : Long.valueOf(concurrentMap.get(SEND_NUM).toString());

            yzmNum = concurrentMap.get(YZM_NUM) == null ? 0 : Long.valueOf(concurrentMap.get(YZM_NUM).toString());
//            yzmNumSending = concurrentMap.get(YZM_NUM_SENDING) == null ? 0 : Long.valueOf(concurrentMap.get(YZM_NUM_SENDING).toString());

            majorNum = concurrentMap.get(MAJOR_NUM) == null ? 0 : Long.valueOf(concurrentMap.get(MAJOR_NUM).toString());
//            majorNumSending = concurrentMap.get(MAJOR_NUM_SENDING) == null ? 0 : Long.valueOf(concurrentMap.get(MAJOR_NUM_SENDING).toString());

            ordinaryNum = concurrentMap.get(ORDINARY_NUM) == null ? 0 : Long.valueOf(concurrentMap.get(ORDINARY_NUM).toString());
//            ordinaryNumSending = concurrentMap.get(ORDINARY_NUM_SENDING) == null ? 0 : Long.valueOf(concurrentMap.get(ORDINARY_NUM_SENDING).toString());

            if(yzmNum==0&&YZM_NUM.equals(auditPageName)){
                result.put(YZM_NUM,rc);
                result.put(YZM_NUM_SENDING,rc);
            }

            if(majorNum==0&&MAJOR_NUM.equals(auditPageName)){
                result.put(MAJOR_NUM,rc);
                result.put(MAJOR_NUM_SENDING,rc);
            }

            if(ordinaryNum==0&&ORDINARY_NUM.equals(auditPageName)){
                result.put(ORDINARY_NUM,rc);
                result.put(ORDINARY_NUM_SENDING,rc);
            }

        }

        return result;
    }



    long refreshTimeMinute;

    public static void main(String[] args) {
        DateTime now = new DateTime();
        System.out.println(now.getMillis());
    }

    @Override
    @Scheduled(cron = "0/10 * * * * ?") // 15秒执行一次
    public void refreshDFATreeCache() {
        LOGGER.debug("refreshDFATreeCache begin");
        long begin = System.currentTimeMillis();
        int expireTime = ConfigUtils.audit_client_keyword_expire_time;
        int auditExpireTime = ConfigUtils.audit_cache_expire_time;

        long now = new Date().getTime()/1000/60;
        LOGGER.debug("refreshDFATreeCache expireTime={},now={}",expireTime,now);
        if(refreshTimeMinute!=now){
            refreshTimeMinute = now;
        }else{ //已经执行过了
            return;
        }

//        if(now%expireTime==0){ //每expireTime时间，执行一次
//            JsmsPage page = new JsmsPage();
//            page.setRows(-1);
//            List<JsmsAccount> accounts = jsmsAccountService.queryList(page).getData();
//            for(JsmsAccount account:accounts){
//                LOGGER.debug("refreshDFATreeCache clientId={}",account.getClientid());
//                dfaTreeCache.remove(account.getClientid());
//                this.putClientAuditKeywordAndCategoryInCahche(account.getClientid());
//            }
//        }

        if(now%expireTime==0) { //每expireTime时间，执行一次
            List<String> clientIds = new ArrayList<>();
                for (Map.Entry<String, DFAUtil4AuditUtil.DFANode4Audit<String>> entry : dfaTreeCache.entrySet()) {
                clientIds.add(entry.getKey());
            }
            LOGGER.info("refresh dfaTreeCache clientids={}", com.jsmsframework.common.util.JsonUtil.toJson(clientIds));
            for(String c:clientIds){
                dfaTreeCache.remove(c);
                this.putClientAuditKeywordAndCategoryInCahche(c);
            }
            LOGGER.info("refresh dfaTreeCache finish cost {}ms",System.currentTimeMillis()-begin);


            LOGGER.info("refresh auditCache begin");
            long auditRefreshBegin = System.currentTimeMillis();
            long runNow = new Date().getTime();
            List<String> auditids = new ArrayList<>();
            for(Map.Entry<String,Map<String,Object>> entry:auditCache.entrySet()){
                Map<String,Object> audit = entry.getValue();
                DateTime cacheTime = (DateTime) audit.get("cacheTime");
                long interval = (runNow - cacheTime.getMillis())/1000;
                if(interval>auditExpireTime){
                    LOGGER.debug("auditCache expire audit={}", com.jsmsframework.common.util.JsonUtil.toJson(audit));
                    auditids.add(entry.getKey());
                }
            }
            LOGGER.debug("auditCache expire auditids={}", com.jsmsframework.common.util.JsonUtil.toJson(auditids));
            for(String a:auditids){
                auditCache.remove(a);
            }
            LOGGER.info("refresh auditCache finish cost {}ms",System.currentTimeMillis()-auditRefreshBegin);



        }

        if(now%30==0){ //半小时监控下缓存的情况
            ThreadPool.submit(new Callable<Object>() {
                private  Logger logger = LoggerFactory.getLogger("dfaTreeCacheLog");
                @Override
                public Object call() throws Exception {
                    logger.debug("snapshot dfaTreeCache begin");
                    long snapshotBegin = System.currentTimeMillis();
                    SmsAuditService smsAuditService = SpringContextUtils.getBean(SmsAuditService.class);
                    Map<String, DFAUtil4AuditUtil.DFANode4Audit<String>> dfaNode4AuditMap = smsAuditService.getDfaTreeCache();
                    for (Map.Entry<String, DFAUtil4AuditUtil.DFANode4Audit<String>> entry : dfaTreeCache.entrySet()) {
                        logger.debug(" dfaTreeCache snapshot key={}, value={}",entry.getKey(),toLogString(entry.getValue()));
                    }

                    logger.debug("snapshot dfaTreeCache end cost {}ms",System.currentTimeMillis()-snapshotBegin);

                    return null;
                }

                /**
                 * 简单的遍历第一层节点，后续再完整的输出
                 * @param value
                 * @return
                 */
                private String toLogString(DFAUtil4AuditUtil.DFANode4Audit<String> value) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("category=").append(toJson(value.getCategory())).append(", ")//
                    .append("AuditClientGroupIsDefault=").append(value.getAuditClientGroupIsDefault()).append(", ")//
                    .append("T={");

                    for(DFAUtil.DFANode<String> firtChild:value.getDfaNodes()){
                        sb.append(firtChild.getValue()).append(", ");
                    }
                    sb.append("}");
                    return sb.toString();

                }
            });  //输出dfaTreeCache
            ThreadPool.submit(new Callable<Object>(){
                private  Logger logger = LoggerFactory.getLogger("auditCacheLog");
                @Override
                public Object call() throws Exception {
                    logger.debug("snapshot auditCache begin");
                    long snapshotBegin = System.currentTimeMillis();
                    SmsAuditService smsAuditService = SpringContextUtils.getBean(SmsAuditService.class);
                    Map<String, Map<String, Object>> auditMap = smsAuditService.getAuditCache();
                    for(Map.Entry<String,Map<String,Object>> entry:auditMap.entrySet()){
                            LOGGER.debug("auditCache snapshot audit={}", toJson(entry.getValue()));
                    }

                    logger.debug("snapshot auditCache end cost {}ms",System.currentTimeMillis()-snapshotBegin);
                    return null;
                }
            });  //输出auditCache
        }

        LOGGER.debug("refreshDFATreeCache end cost {}ms",System.currentTimeMillis()-begin);
    }


    @Override
    public Map<String, DFAUtil4AuditUtil.DFANode4Audit<String>> getDfaTreeCache() {
        return dfaTreeCache;
    }

    @Override
    public Map<String, Map<String, Object>> getAuditCache() {
        return auditCache;
    }


    static final String SPLIT = "-";
    @Override
    @Scheduled(cron = "0/10 * * * * ?") // 15秒执行一次
    public void updateKindsAuditNum() {
//        if(ConfigUtils.envrionment!=null&&ConfigUtils.envrionment.equals("development")) //开发环境不执行这任务，不然很多日志
//            return;
        try {
            long auditNum = 0;                                                          //待审核短信数量(总的)
            long auditNumSending = 0;                                                   //审核待发送数(总的)
            long yzmNum = 0;                                                            //待审核短信数量(验证码短信审核)
            long yzmNumSending = 0;                                                     //审核待发送数(验证码短信审核)
            long majorNum = 0;                                                          //待审核短信数量(重点客户短信审核)
            long majorNumSending = 0;                                                   //审核待发送数(重点客户短信审核)
            long ordinaryNum = 0;                                                       //待审核短信数量(普通短信)
            long ordinaryNumSending = 0;                                                //审核待发送数(普通短信)


            //重点客户
            final Set<String> clientIds = getMajorClientIds();
            concurrentMap.put(MAJOR_CLIENTS, clientIds);
            Future<String> majorNumFuture = null;
            if (!clientIds.isEmpty()) { //设置重点客户短信数量
                majorNumFuture = ThreadPool.submit(new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        Map<String, Object> sqlParam = new HashMap();
                        sqlParam.put("clientIds", clientIds);
                        Map<String, Object> major = messageMasterDao.getOneInfo("smsAudit.getMojorAuditNum", sqlParam);
                        return major.get(MAJOR_NUM).toString() + SPLIT + major.get(MAJOR_NUM_SENDING).toString();
                    }
                });
                LOGGER.debug("submit major number query task");

            }

            //汇总
            Future<String> auditNumFuture = ThreadPool.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Map<String, Object> total = messageMasterDao.getOneInfo("smsAudit.getNeedAuditNum", null);
                    return total.get(AUDIT_NUM).toString() + SPLIT + total.get(SEND_NUM).toString();
                }
            });
            LOGGER.debug("submit audit(total) number query task");


            //验证码类别
            Future<String> yzmNumFuture = ThreadPool.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Map<String, Object> yzm = messageMasterDao.getOneInfo("smsAudit.getYZMAuditNum", null);
                    return yzm.get(YZM_NUM).toString() + SPLIT + yzm.get(YZM_NUM_SENDING).toString();
                }
            });
            LOGGER.debug("submit yzm number query task");

            String auditStr[] = auditNumFuture.get().split(SPLIT);
            String yzmStr[] = yzmNumFuture.get().split(SPLIT);
            String majorStr[] = majorNumFuture.get().split(SPLIT);

            auditNum = Long.valueOf(auditStr[0]);
            auditNumSending = Long.valueOf(auditStr[1]);
            yzmNum = Long.valueOf(yzmStr[0]);
            yzmNumSending = Long.valueOf(yzmStr[1]);
            majorNum = Long.valueOf(majorStr[0]);
            majorNumSending = Long.valueOf(majorStr[1]);


            concurrentMap.put(AUDIT_NUM, auditNum);                                     //待审核短信数量(总的，不分级别)
            concurrentMap.put(SEND_NUM, auditNumSending);                               //待发送数量(总的，不分级别)
            concurrentMap.put(YZM_NUM, yzmNum);                                         //待审核短信数量(验证码短信审核)
            concurrentMap.put(YZM_NUM_SENDING, yzmNumSending);                          //审核待发送数(验证码短信审核)
            concurrentMap.put(MAJOR_NUM, majorNum);                                     //待审核短信数量(重点客户短信审核)
            concurrentMap.put(MAJOR_NUM_SENDING, majorNumSending);                      //审核待发送数(重点客户短信审核)


            //普通短信
            ordinaryNum = auditNum - yzmNum - majorNum;
            ordinaryNumSending = auditNumSending - yzmNumSending - majorNumSending;
            if (ordinaryNum < 0 || ordinaryNumSending < 0) {
                Map<String, Object> total = messageMasterDao.getOneInfo("smsAudit.getNeedAuditNum", null);
                auditNum = Long.valueOf(total.get(AUDIT_NUM).toString());
                auditNumSending = Long.valueOf(total.get(SEND_NUM).toString());
                concurrentMap.put(AUDIT_NUM, auditNum);
                ordinaryNum = auditNum - yzmNum - majorNum;
                ordinaryNumSending = auditNumSending - yzmNumSending - majorNumSending;
            }


            concurrentMap.put(ORDINARY_NUM, ordinaryNum > 0 ? ordinaryNum : 0);
            concurrentMap.put(ORDINARY_NUM_SENDING, ordinaryNumSending > 0 ? ordinaryNumSending : 0);
        }catch (Exception e){
            LOGGER.error("统计短信审核记录数异常",e);
        }

    }

    @Override
//    @Scheduled(cron = "* 0/10 * * * ?") // 10分钟执行一次
    public void cacheKindsAuditId() {
        // todo
    }

    private void checkLockNum(Map<String, Object> map) {
        Set<String> majorAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + MAJOR_NUM + ":*");
        Set<String> yzmAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + YZM_NUM + ":*");
        Set<String> ordinaryAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + ORDINARY_NUM + ":*");
        map.put(MAJOR_LOCK_NUM, majorAuditLock == null ? 0 : majorAuditLock.size());
        map.put(YZM_LOCK_NUM, yzmAuditLock == null ? 0 : yzmAuditLock.size());
        map.put(ORDINARY_LOCK_NUM, ordinaryAuditLock == null ? 0 : ordinaryAuditLock.size());
    }

    private Set<String> getMajorClientIds() {
        List<JsmsClientInfoExt> auditKeyAccountInfoExt = jsmsClientInfoExtService.getAuditKeyAccountInfoExt();
        Set<String> clientIds = new TreeSet<>();
        for (JsmsClientInfoExt jsmsClientInfoExt : auditKeyAccountInfoExt) {
            clientIds.add(jsmsClientInfoExt.getClientid());
        }
        return clientIds;
    }

    /**
     * 查询审核超时时间<br>
     * 单位：分钟
     */
    @Override
    public Map<String, Object> getAuditExpireTime() {
        Map<String, Object> data = messageMasterDao.getOneInfo("smsAudit.getAuditExpireTime", null);
        String resultContent = "";
        int auditExpireTime = 15;// 默认短信审核超时时间
        try {
            if (null != data && null != data.get("auditExpireTime")) {
                resultContent = (String) data.get("auditExpireTime");
                if (StringUtils.isNotBlank(resultContent)) {
                    auditExpireTime = Integer.valueOf(resultContent.split(";")[0]);
                }
            }
        } catch (Exception e) {
            LOGGER.error("查询审核超时时间是发送错误：" + e);
        }

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put("auditExpireTime", auditExpireTime);
        return resultMap;
    }


    /**
     * 查询“待审核记录数”、“待发送数”、“锁定审核记录数”
     */
    @Override
    public Map<String, Object> getNeedAuditNum() {
        int auditNum = 0;
        int sendNum = 0;
        int lockNum = 0;

        // 查询审核状态为0和3的记录然后计算出审核记录数和待发送数
        Map<String, Object> data = messageMasterDao.getOneInfo("smsAudit.getNeedAuditNum", null);
        if (data != null) {
            auditNum = Integer.valueOf(String.valueOf(data.get(AUDIT_NUM)));
            sendNum = Integer.valueOf(String.valueOf(data.get(SEND_NUM)));
        }

        // 查询当前已经锁定的审核记录数
        Set<String> keySet = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + "*");
        lockNum = keySet == null ? 0 : keySet.size();

        Map<String, Object> resultMap = new HashMap<String, Object>();
        resultMap.put(AUDIT_NUM, auditNum);
        resultMap.put(SEND_NUM, sendNum);
        resultMap.put(LOCK_NUM, lockNum);
        checkLockNum(resultMap);
//        Set<String> majorAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + MAJOR_NUM +":*");
//        Set<String> yzmAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + YZM_NUM +":*");
//        Set<String> ordinaryAuditLock = RedisUtils.getKeysSpecifiedDb(6, SMS_AUDIT_LOCKED + AUDIT_NUM +":*");

        return resultMap;
    }


    /**
     * 短信审核查询页面
     *
     * @param page
     * @return
     */
    @Override
    public JsmsPage hisauditQueryPage(JsmsPage page) {

        if (page.getParams().get("aduitor") != null) {
            JsmsPage usepage = new JsmsPage();
            usepage.getParams().put("realname", page.getParams().get("aduitor"));
            usepage.setRows(99); //哥不信有那么多重名
            usepage = jsmsUserService.queryList(usepage);
            List<JsmsUser> user = usepage.getData();
            List auditIds = new ArrayList();
            for (JsmsUser jsmsUser : user) {

                auditIds.add(jsmsUser.getId());
            }

            page.getParams().put("auditperson", auditIds);
        }

        page.setOrderByClause("audittime desc");

        List<JsmsAuditDTO> result = new ArrayList<>();
        JsmsPage pages = jsmsAuditService.queryList(page);
        List<JsmsAudit> list = pages.getData();
        int i = 0;
        int rownum = 1;
        if (!list.isEmpty() || list.size() > 0) {
            for (JsmsAudit jsmsAudit : list) {
                JsmsAuditDTO dto = new JsmsAuditDTO();
                BeanUtil.copyProperties(jsmsAudit, dto);
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.通知.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.通知.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.验证码.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.验证码.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.营销.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.营销.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.告警.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.告警.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.USSD.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.USSD.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.闪信.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.闪信.getDesc());
                }

                if (jsmsAudit.getStatus().equals(AuditType.待审核.getValue())) {
                    dto.setStatusName(AuditType.待审核.getDesc());
                }
                if (jsmsAudit.getStatus().equals(AuditType.审核通过.getValue())) {
                    dto.setStatusName(AuditType.审核通过.getDesc());
                }
                if (jsmsAudit.getStatus().equals(AuditType.审核不通过.getValue())) {
                    dto.setStatusName(AuditType.审核不通过.getDesc());
                }
                if (jsmsAudit.getStatus().equals(AuditType.转审.getValue())) {
                    dto.setStatusName(AuditType.转审.getDesc());
                }
                if (jsmsAudit.getAuditperson() != null) {
                    Long id = Long.valueOf(jsmsAudit.getAuditperson());
                    JsmsUser audits = jsmsUserService.getById(String.valueOf(id));
                    if (audits != null) {
                        dto.setAuditpersonName(audits.getRealname());
                    } else {
                        dto.setAuditpersonName("未知");
                    }

                }
                if (StringUtils.isNoneBlank(jsmsAudit.getTransferperson())) {
                    Long id = Long.valueOf(jsmsAudit.getTransferperson());
                    JsmsUser tranUser = jsmsUserService.getById(String.valueOf(id));
                    if (tranUser != null) {
                        dto.setTransferpersonName(tranUser.getRealname());
                    } else {
                        dto.setTransferpersonName("未知");
                    }

                }
                if (jsmsAudit.getCreatetime() != null) {
                    dto.setCreatetimeStr(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jsmsAudit.getCreatetime()));

                } else {
                    dto.setCreatetimeStr("-");
                }
                if (jsmsAudit.getAudittime() != null) {
                    dto.setAudittimeStr(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jsmsAudit.getAudittime()));
                } else {
                    dto.setAudittimeStr("-");
                }


                rownum = (pages.getPage() - 1) * pages.getRows() + 1 + i;
                i++;
                dto.setRownum(rownum);
                result.add(dto);
            }
        }
//		pages.setTotalRecord(jsmsAuditService.countHis(page));
        pages.setData(result);
        return pages;
    }

    /**
     * 短信审核查询页面
     *
     * @param page
     * @return
     */
    @Override
    public JsmsPage hisbakauditQueryPage(JsmsPage page) {

        if (page.getParams().get("aduitor") != null) {
            JsmsPage usepage = new JsmsPage();
            usepage.getParams().put("realname", page.getParams().get("aduitor"));
            usepage.setRows(99); //哥不信有那么多重名+1
            usepage = jsmsUserService.queryList(usepage);
            List<JsmsUser> user = usepage.getData();
            List auditIds = new ArrayList();
            for (JsmsUser jsmsUser : user) {

                auditIds.add(jsmsUser.getId());
            }

            page.getParams().put("auditperson", auditIds);
        }

        page.setOrderByClause("audittime desc");
        List<JsmsAuditDTO> result = new ArrayList<>();
        JsmsPage pages = jsmsAuditService.queryList(page);
        List<JsmsAudit> list = pages.getData();
        int i = 0;
        int rownum = 1;
        if (!list.isEmpty() || list.size() > 0) {
            for (JsmsAudit jsmsAudit : list) {
                JsmsAuditDTO dto = new JsmsAuditDTO();
                BeanUtil.copyProperties(jsmsAudit, dto);
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.通知.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.通知.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.验证码.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.验证码.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.营销.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.营销.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.告警.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.告警.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.USSD.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.USSD.getDesc());
                }
                if (jsmsAudit.getSmstype().equals(SmsTypeEnum.闪信.getValue())) {
                    dto.setSmsTypeName(SmsTypeEnum.闪信.getDesc());
                }

                if (jsmsAudit.getStatus().equals(AuditType.待审核.getValue())) {
                    dto.setStatusName(AuditType.待审核.getDesc());
                }
                if (jsmsAudit.getStatus().equals(AuditType.审核通过.getValue())) {
                    dto.setStatusName(AuditType.审核通过.getDesc());
                }
                if (jsmsAudit.getStatus().equals(AuditType.审核不通过.getValue())) {
                    dto.setStatusName(AuditType.审核不通过.getDesc());
                }
                if (jsmsAudit.getStatus().equals(AuditType.转审.getValue())) {
                    dto.setStatusName(AuditType.转审.getDesc());
                }
                if (jsmsAudit.getAuditperson() != null) {
                    Long id = Long.valueOf(jsmsAudit.getAuditperson());
                    JsmsUser audits = jsmsUserService.getById(String.valueOf(id));
                    if (audits != null) {
                        dto.setAuditpersonName(audits.getRealname());
                    } else {
                        dto.setAuditpersonName("未知");
                    }

                }
                if (jsmsAudit.getTransferperson() != null) {
                    Long id = Long.valueOf(jsmsAudit.getTransferperson());
                    JsmsUser tranUser = jsmsUserService.getById(String.valueOf(id));
                    if (tranUser != null) {
                        dto.setTransferpersonName(tranUser.getRealname());
                    } else {
                        dto.setTransferpersonName("未知");
                    }

                }
                if(!Objects.equals(jsmsAudit.getStatus(), com.jsmsframework.common.enums.audit.AuditStatus.审核不通过.getValue())){
                    dto.setOptRemark("-");
                }
                if(Objects.equals(jsmsAudit.getStatus(), com.jsmsframework.common.enums.audit.AuditStatus.审核不通过转人工过期.getValue())){

                    dto.setAuditpersonName(dto.getTransferpersonName());
                }

                if (jsmsAudit.getCreatetime() != null) {
                    dto.setCreatetimeStr(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jsmsAudit.getCreatetime()));

                } else {
                    dto.setCreatetimeStr("-");
                }
                if (jsmsAudit.getAudittime() != null) {
                    dto.setAudittimeStr(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jsmsAudit.getAudittime()));
                } else {
                    dto.setAudittimeStr("-");
                }


                rownum = (pages.getPage() - 1) * pages.getRows() + 1 + i;
                i++;
                dto.setRownum(rownum);
                result.add(dto);
            }
        }
//		pages.setTotalRecord(jsmsAuditService.countHis(page));
        pages.setData(result);
        return pages;
    }

    /**
     * 查询历史审核记录
     *
     * @param params
     * @return
     */
    @Override
    public List<Map<String, Object>> queryhisAll(Map<String, String> params) {
        Map<String, Object> params1 = new HashMap<>();
        params1.putAll(params);
        if (params.get("aduitor") != null) {
            JsmsPage usepage = new JsmsPage();
            usepage.getParams().put("realname", params.get("aduitor"));
            usepage.setRows(99);  //哥不信有那么多重名+2
            usepage = jsmsUserService.queryList(usepage);
            List<JsmsUser> user = usepage.getData();
            List auditIds = new ArrayList();
            for (JsmsUser jsmsUser : user) {

                auditIds.add(jsmsUser.getId());
            }

            params1.put("auditperson", auditIds);
        }

        List<Map<String, Object>> result = new ArrayList<>();
        List<Map<String, Object>> list = jsmsAuditService.queryhisAll(params1);
        int i = 0;
        int rownum = 1;
        if (!list.isEmpty() || list.size() > 0) {
            for (Map<String, Object> map : list) {
                rownum = 1 + i;
                i++;
                map.put("rownum", rownum);
                result.add(map);
            }
        }

        return result;
    }

    /**
     * 查询历史审核记录
     *
     * @param params
     * @return
     */
    @Override
    public List<Map<String, Object>> queryhisbakAll(Map<String, String> params) {
        Map<String, Object> params1 = new HashMap<>();
        params1.putAll(params);
        if (params.get("aduitor") != null) {
            JsmsPage usepage = new JsmsPage();
            usepage.getParams().put("realname", params.get("aduitor"));
            usepage.setRows(99);  //哥不信有那么多重名+2
            usepage = jsmsUserService.queryList(usepage);
            List<JsmsUser> user = usepage.getData();
            List auditIds = new ArrayList();
            for (JsmsUser jsmsUser : user) {

                auditIds.add(jsmsUser.getId());
            }

            params1.put("auditperson", auditIds);
        }

        List<Map<String, Object>> result = new ArrayList<>();
        List<Map<String, Object>> list = jsmsAuditBakService.queryhisAll(params1);
        int i = 0;
        int rownum = 1;
        if (!list.isEmpty() || list.size() > 0) {
            for (Map<String, Object> map : list) {
                rownum = 1 + i;
                i++;
                map.put("rownum", rownum);
                result.add(map);
            }
        }

        return result;
    }

    @Override
    @Transactional
    public Map<String, Object> setAuditExpired(String auditId) throws Exception {
        LOGGER.debug("userId={}将aduitid={}审核过期", AuthorityUtils.getLoginUserId(), auditId);
        Map<String, Object> result = new HashMap<>();
        if (StringUtils.isBlank(auditId)) {
            result.put("result", "fail");
            result.put("msg", "审核ID不能为空");
            return result;
        }

        messageMasterDao.update("smsAudit.updateAuditExpired", auditId);


        JsmsAudit audit = jsmsAuditService.getByAuditid(Long.valueOf(auditId));
        audit.setReadedflag(2);
        LOGGER.debug("audit={}", audit);
        LOGGER.debug("推送消息到mq");
        /**
         * 	1：审核通过，
         2：审核不通过，
         3：审核通过转人工过期，
         4：审核不通过转人工过期

         */
        if (audit.getStatus().intValue() == com.jsmsframework.common.enums.audit.AuditStatus.审核通过.getValue().intValue()) {  //
            audit.setStatus(com.jsmsframework.common.enums.audit.AuditStatus.审核通过转人工过期.getValue());
        } else if (audit.getStatus().intValue() == com.jsmsframework.common.enums.audit.AuditStatus.审核不通过.getValue().intValue()) {
            audit.setStatus(com.jsmsframework.common.enums.audit.AuditStatus.审核不通过转人工过期.getValue());
        }

        try {
            publishAuditResultToMQ(audit);
        } catch (Exception e) {
            LOGGER.error("推送消息至MQ失败", e);
            throw e;
        }

        result.put("result", "success");
        result.put("msg", "操作成功");
        return result;
    }

}
